package com.apobates.forum.thrones.controller;

import com.apobates.forum.core.ImageIOMeta;
import com.apobates.forum.core.entity.Album;
import com.apobates.forum.core.entity.AlbumPicture;
import com.apobates.forum.core.entity.Board;
import com.apobates.forum.core.entity.BoardGroup;
import com.apobates.forum.core.entity.BoardStats;
import com.apobates.forum.core.entity.ForumEntityStatusEnum;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.TopicCategory;
import com.apobates.forum.core.entity.proxy.BoardGroupReplica;
import com.apobates.forum.core.entity.proxy.TopicReplica;
import com.apobates.forum.core.service.AlbumPictureService;
import com.apobates.forum.core.service.AlbumService;
import com.apobates.forum.core.service.BoardGroupService;
import com.apobates.forum.core.service.BoardModeratorService;
import com.apobates.forum.core.service.BoardService;
import com.apobates.forum.core.service.BoardStatsService;
import com.apobates.forum.core.service.BoardTopicCategoryIndexService;
import com.apobates.forum.core.service.TopicService;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.thrones.vo.ForumBoardStats;
import com.apobates.forum.thrones.vo.ForumBoardStatsRecord;
import com.apobates.forum.thrones.vo.ForumThreads;
import com.apobates.forum.thrones.vo.ForumThreadsDigest;
import com.apobates.forum.thrones.vo.ThreadsAlbumPicture;
import com.apobates.forum.utils.lang.CommonBean;
import com.apobates.forum.utils.Commons;
import com.google.gson.Gson;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 异步加载的控制器
 *
 * @author xiaofanku
 * @since 20200525
 */
@Controller
@RequestMapping(value = "/loader")
public class LazyLoadController {
    @Autowired
    private BoardGroupService boardGroupService;
    @Autowired
    private BoardService boardService;
    @Autowired
    private BoardStatsService boardStatsService;
    @Autowired
    private BoardModeratorService boardModeratorService;
    @Autowired
    private BoardTopicCategoryIndexService boardTopicCategoryIndexService;
    @Autowired
    private TopicService topicService;
    @Autowired
    private AlbumService albumService;
    @Autowired
    private AlbumPictureService albumPictureService;
    @Autowired
    private ImageIOMeta imageIOMeta;
    // ----------------------------------------------------------------------版块组的
    // [发布主题]版块组(卷)列表[OK]
    // 可发贴的
    @GetMapping(path = "/volumes/usable.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<CommonBean> getAllBoardGroup(HttpServletRequest request, Model model) {
        List<CommonBean> data = boardGroupService.getAllUsed().stream().map(bg -> new CommonBean(bg.getId(), bg.getTitle())).collect(Collectors.toList());
        // 增补默认版块组(卷)
        BoardGroup defaultGroup = BoardGroup.defaultInstance();
        data.add(new CommonBean(defaultGroup.getId(), defaultGroup.getTitle()));
        return data;
    }
    
    // 版块组下的热门话题[OK]
    @GetMapping(path = "/volumes/topic/hot.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<ForumThreadsDigest> getHotTopic(@RequestParam("id") int boardGroupId, HttpServletRequest request, Model model) {
        return topicService.getMaxReplyForBoardGroup(boardGroupId, 10).map(ForumThreadsDigest::new).collect(Collectors.toList());
    }
    
    // 版块组下的精华话题[OK]
    @GetMapping(path = "/volumes/topic/best.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<ForumThreadsDigest> getBestTopic(@RequestParam("id") int boardGroupId, HttpServletRequest request, Model model) {
        return topicService.getGoodsForBoardGroup(boardGroupId, 10).map(ForumThreadsDigest::new).collect(Collectors.toList());
    }
    
    // 版块组下最近的话题[OK]
    @GetMapping(path = "/volumes/topic/recent.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String getVolumesRecentTopic(
            @RequestParam("id") int boardGroupId,
            @RequestParam(value = "size", required = false, defaultValue = "0") int showSize,
            HttpServletRequest request,
            Model model) {
        int ss = (showSize == 0) ? 10 : showSize;
        List<ForumThreads> data = topicService.getRecent(boardGroupId, ss).sorted(Comparator.comparing(Topic::getRankingDateTime).reversed()).map(ForumThreads::new).collect(Collectors.toList());
        return new Gson().toJson(data);
    }
    // 大版块下所有在线的大版主
    @GetMapping(path = "/volumes/moderator.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<CommonBean> getBoardGroupModeratores(
            @RequestParam("id") int boardGroupId,
            HttpServletRequest request,
            Model model) {
        return boardModeratorService.getAllUsedByBoardGroupId(boardGroupId).map(bm -> new CommonBean(bm.getMemberId(), bm.getMemberNickname())).collect(Collectors.toList());
    }
    // 服务于版块导航[OK]
    // key=CommonBean(版块组ID, 版块组名称), value=版块组下的版块
    @GetMapping(path = "/board/select.jsonp", produces = "application/javascript;charset=UTF-8")
    @ResponseBody
    public String getAllBoardGroupAndBoard(
            @RequestParam("callback") String callBackFun,
            @RequestParam(value = "box", required = false, defaultValue = "null") String boxEle,
            HttpServletRequest request,
            Model model) {
        List<BoardGroupReplica> rs = boardGroupService.getAllUsedAndBoard(false);
        if (rs.isEmpty()) {
            return callBackFun + "({});";
        }
        Function<BoardGroupReplica, String> keyMapper = bg -> bg.getTitle();
        Function<BoardGroupReplica, List<Map<String, String>>> valueMapper = bg -> {
            return bg.getBoardes().stream().map(b -> {
                String key = b.getId() + "-" + bg.getId();
                HashMap<String, String> tmp = new HashMap<>();
                tmp.put(key, b.getTitle());
                return tmp;
            }).collect(Collectors.toList());
        };
        Map<String, List<Map<String, String>>> data = rs.stream().collect(Collectors.toConcurrentMap(keyMapper, valueMapper));
        Map<String, Object> result = Map.ofEntries(Map.entry("element", boxEle), Map.entry("result", data));
        return callBackFun + "(" + new Gson().toJson(result) + ");";
    }
    
    // 由于采用缓存.导致版块的统计显示错误[OK]
    // 版块列表[所有版块的统计]
    /* 版块组内容页[指定版块的统计] */
    @GetMapping(path = "/board/stats.jsonp", produces = "application/javascript;charset=UTF-8")
    @ResponseBody
    public String getBoardStatsForJsonp(
            @RequestParam("ids") String boardIdString,
            @RequestParam("callback") String callBackFun,
            HttpServletRequest request,
            Model model) {
        Set<Long> boardIdSet = Commons.toLongSet(boardIdString);
        if (null == boardIdSet || boardIdSet.isEmpty()) {
            return callBackFun + "({});";
        }
        List<ForumBoardStatsRecord> data = boardStatsService.getFillTodayTopices(boardIdSet).map(ForumBoardStatsRecord::new).collect(Collectors.toList());
        if (data.isEmpty()) {
            return callBackFun + "({});";
        }
        Map<String, Object> result = Map.ofEntries(Map.entry("result", data));
        return callBackFun + "(" + new Gson().toJson(result) + ");";
    }
    
    // ----------------------------------------------------------------------版块的
    // [发布主题]指定版块组(卷)下的版块[OK]
    // 可发贴的
    @GetMapping(path = "/volumes/board.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<CommonBean> getAllBoardByBoardGroup(
            @RequestParam("volumes") int boardGroupId,
            HttpServletRequest request,
            Model model) {
        return boardService.getAllUsedByVolumesId(boardGroupId).stream().filter(b -> ForumEntityStatusEnum.ACTIVE == b.getStatus()).map(b -> new CommonBean(b.getId(), b.getTitle())).collect(Collectors.toList());
    }
    
    // 编辑
    // ETC
    // 话题移动需要的版块[OK]
    @GetMapping(path = "/board/except.jsonp", produces = "application/javascript;charset=UTF-8")
    @ResponseBody
    public String getAllBoard(
            @RequestParam("callback") String callBackFun,
            @RequestParam(value = "box", required = false, defaultValue = "null") String boxEle,
            @RequestParam("board") long exceptBoardId,
            HttpServletRequest request,
            Model model) {
        List<CommonBean> rs = boardService.getAllUsed().filter(b -> b.getId() != exceptBoardId).map(b -> new CommonBean(b.getId(), b.getTitle())).collect(Collectors.toList());
        if (rs.isEmpty()) {
            return callBackFun + "({});";
        }
        Map<String, Object> result = Map.ofEntries(Map.entry("element", boxEle), Map.entry("result", rs));
        return callBackFun + "(" + new Gson().toJson(result) + ");";
    }
    
    // 某版块的版主[OK]
    @GetMapping(path = "/board/moderator.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<CommonBean> getBoardModeratores(
            @RequestParam("id") long boardId,
            HttpServletRequest request,
            Model model) {
        return boardModeratorService.getAllUsedByBoardId(boardId).stream().map(bm -> new CommonBean(bm.getMemberId(), bm.getMemberNickname())).collect(Collectors.toList());
    }
    
    // [/home]右侧的版块统计[OK]
    @GetMapping(path = "/stats/board.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<ForumBoardStats> getBoardStats(HttpServletRequest request, Model model) {
        Map<Long, BoardStats> rs = boardStatsService.getAll().collect(Collectors.toMap(BoardStats::getBoardId, Function.identity()));
        Map<Long, String> boardNames = boardService.getAllById(rs.keySet());
        //
        BiFunction<BoardStats, String, ForumBoardStats> biFunction = (bs, boardName) -> {
            if(null == boardName){
                return null;
            }
            Board b = new Board();
            b.setTitle(boardName);
            b.setId(bs.getBoardId());
            b.setVolumesId(bs.getVolumesId());
            return new ForumBoardStats(b, bs.getPostses(), bs.getTopices());
        };
        return rs.keySet().stream().mapToLong(Long::valueOf).mapToObj(boardId->biFunction.apply(rs.get(boardId), boardNames.get(boardId))).filter(Objects::nonNull).collect(Collectors.toList());
    }
    
    // [版块列表]底部的话题和回复统计汇总[OK]
    @GetMapping(path = "/stats/collect.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public Map<String, Long> getBoardStatsCollect(HttpServletRequest request, Model model) {
        Map<ForumActionEnum, Long> statsdata = boardStatsService.sumTopicAndPosts();
        Function<Entry<ForumActionEnum, Long>, String> keyMapper = entry->{
            return ForumActionEnum.POSTS_REPLY == entry.getKey()?"replies":"threads";
        };
        Function<Entry<ForumActionEnum, Long>, Long> valueMapper = entry->Commons.optional(entry.getValue(), 0L);
        return statsdata.entrySet().stream().collect(Collectors.toMap(keyMapper, valueMapper));
    }
    
    // ----------------------------------------------------------------------话题的
    // 某版块置顶的话题[OK]
    @GetMapping(path = "/board/top.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<ForumThreads> getBoardTopTopic(@RequestParam("board") long boardId, HttpServletRequest request, Model model) {
        return topicService.getTopForBoard(boardId).map(ForumThreads::new).collect(Collectors.toList());
    }
    
    // 指定版块可以发布的话题类型[OK]
    @GetMapping(path = "/board/category.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<CommonBean> getBoardTopicCategories(
            @RequestParam("volumes") int boardGroupId,
            @RequestParam("board") long boardId,
            HttpServletRequest request,
            Model model) {
        Set<TopicCategory> categories = new HashSet<>();
        if (boardGroupId >= 0 && boardId > 0) {
            categories = boardTopicCategoryIndexService.getAllByBoardTopicCategories(boardGroupId, boardId).collect(Collectors.toSet());
        } else {
            categories.add(TopicCategory.empty());
        }
        return categories.stream().map(tc -> new CommonBean(tc.getId(), tc.getNames())).sorted(Comparator.comparing(CommonBean::getId)).collect(Collectors.toList());
    }
    
    // 版块首页(/board/home)右侧的热点话题[OK]
    @GetMapping(path = "/hot.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public List<ForumThreadsDigest> getHotTopices(HttpServletRequest request, Model model) {
        return topicService.getHot(10).map(ForumThreadsDigest::new).collect(Collectors.toList());
    }
    
    // 查看指定像册的所有图片[OK]
    @GetMapping(path = "/album.jsonp", produces = "application/javascript;charset=UTF-8")
    @ResponseBody
    public String getTopicAlbumPicturesForJsonp(
            @RequestParam("album") String albumIdString,
            @RequestParam("callback") String callBackFun,
            @RequestParam(value = "scale", required = false, defaultValue = "150x105") String scale,
            @RequestParam(value = "size", required = false, defaultValue = "5") int showSize,
            HttpServletRequest request,
            Model model) {
        Set<Long> albumIdSet = Commons.toLongSet(albumIdString);
        if (null == albumIdSet || albumIdSet.isEmpty()) {
            return callBackFun + "({});";
        }
        // Key=像册的ID, Value=像册下的图片连接集合
        Map<Long, TreeSet<AlbumPicture>> rs = albumPictureService.getAll(albumIdSet, imageIOMeta, scale, "/static/img/140x140.png", showSize);
        Function<Entry<Long, TreeSet<AlbumPicture>>, Long> keyMapper = entry->entry.getKey();
        Function<Entry<Long, TreeSet<AlbumPicture>>, TreeSet<ThreadsAlbumPicture>> valueMapper = entry->entry.getValue().stream().map(ThreadsAlbumPicture::new).sorted(Comparator.comparing(ThreadsAlbumPicture::getRanking)).collect(Collectors.toCollection(TreeSet::new));
        Map<Long, TreeSet<ThreadsAlbumPicture>> result = rs.entrySet().stream().collect(Collectors.toMap(keyMapper, valueMapper));
        return callBackFun + "(" + new Gson().toJson(result) + ");";
    }
    
    // 话题的封面[未被使用]
    @GetMapping(path = "/cover.jsonp", produces = "application/javascript;charset=UTF-8")
    @ResponseBody
    public String getTopicCoverPictures(
            @RequestParam("topic") String topicIdString,
            @RequestParam("callback") String callBackFun,
            @RequestParam(value = "scale", required = false, defaultValue = "150x105") String scale,
            HttpServletRequest request,
            Model model) {
        Set<Long> topicIdSet = Commons.toLongSet(topicIdString);
        if (null == topicIdSet || topicIdSet.isEmpty()) {
            return callBackFun + "({});";
        }
        // Key=话题的ID, Value=像册下的图片连接集合
        Map<Long, String> result = albumService.getAll(topicIdSet, imageIOMeta, scale, "/static/img/140x140.png").collect(Collectors.toMap(Album::getTopicId, Album::getCoverLink));
        return callBackFun + "(" + new Gson().toJson(result) + ");";
    }

    //查看指定参考日期以来的新话题
    @GetMapping(path = "/board/topic/recent.json", produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String getRecentByPrevStamp(
            @RequestParam("id") String boardIdString,
            @RequestParam("stamp") String refDateStamp,
            HttpServletRequest request,
            Model model){
        long boardId = Commons.stringToLong(boardIdString, 0L);
        int previousUx = Commons.stringToInteger(refDateStamp, 0);
        if(boardId == 0 || previousUx == 0){
            return "{}";
        }
        List<TopicReplica> rs = topicService.getRecentByUnixStamp(boardId, previousUx);
        if (null == rs || rs.isEmpty()) {
            return "{}";
        }
        List<ForumThreads> data = rs.stream().map(ForumThreads::new).collect(Collectors.toList());
        return new Gson().toJson(data);
    }
}